#include "t_avcodec.h"

T_AVFrame::T_AVFrame(AVCodecContext *a_codec_ctx)
    : m_codec_ctx(a_codec_ctx)
{
    m_frame = avcodec_alloc_frame();
}
T_AVFrame::~T_AVFrame()
{
    av_free(m_frame);
}
AVCodecContext *T_AVFrame::codecContext()
{
    return m_codec_ctx;
}
AVFrame *T_AVFrame::frame()
{
    return m_frame;
}
enum PixelFormat T_AVFrame::pix_fmt()
{
    return m_codec_ctx->pix_fmt;
}
int T_AVFrame::width()
{
    return m_codec_ctx->width;
}
int T_AVFrame::height()
{
    return m_codec_ctx->height;
}
uint8_t **T_AVFrame::data()
{
    return m_frame->data;
}
int *T_AVFrame::linesize()
{
    return m_frame->linesize;
}

T_AVPicture::T_AVPicture(PixelFormat a_pix_fmt, int a_width, int a_height)
{
    ctor_T_AVPicture(a_pix_fmt, a_width, a_height);
}
T_AVPicture::T_AVPicture(T_AVImage *a_image)
{
    ctor_T_AVPicture(a_image->pix_fmt(), a_image->width(), a_image->height());
    AVPicture v_pict;
    v_pict.data[0] = a_image->data()[0];
    v_pict.data[1] = a_image->data()[1];
    v_pict.data[2] = a_image->data()[2];
    v_pict.linesize[0] = a_image->linesize()[0];
    v_pict.linesize[1] = a_image->linesize()[1];
    v_pict.linesize[2] = a_image->linesize()[2];
    av_picture_copy(&this->m_av_picture,
                    &v_pict,
                    a_image->pix_fmt(),
                    a_image->width(),
                    a_image->height());
}
T_AVPicture::~T_AVPicture()
{
    if(m_buffer) delete[] m_buffer;
}
enum PixelFormat T_AVPicture::pix_fmt()
{
    return m_pix_fmt;
}
int T_AVPicture::width()
{
    return m_width;
}
int T_AVPicture::height()
{
    return m_height;
}
uint8_t **T_AVPicture::data()
{
    return m_av_picture.data;
}
int *T_AVPicture::linesize()
{
    return m_av_picture.linesize;
}
void T_AVPicture::resize(PixelFormat a_pix_fmt, int a_width, int a_height)
{
    if(m_pix_fmt==a_pix_fmt && m_width==a_width && m_height==a_height) return;
    p_reallocate(a_pix_fmt, a_width, a_height);
}
void T_AVPicture::copyFrom(T_AVImage *a_image)
{
    this->resize(a_image->pix_fmt(),
                 a_image->width(),
                 a_image->height());
    AVPicture v_image_pict;
    v_image_pict.data[0] = a_image->data()[0];
    v_image_pict.data[1] = a_image->data()[1];
    v_image_pict.data[2] = a_image->data()[2];
    v_image_pict.linesize[0] = a_image->linesize()[0];
    v_image_pict.linesize[1] = a_image->linesize()[1];
    v_image_pict.linesize[2] = a_image->linesize()[2];
    av_picture_copy(&this->m_av_picture,
                    &v_image_pict,
                    a_image->pix_fmt(),
                    a_image->width(),
                    a_image->height());
}
void T_AVPicture::scaleFrom(T_AVImage *a_src, int a_sws_flags)
{
    SwsContext *v_sws_ctx = sws_getContext(
            a_src->width(), //int srcW,
            a_src->height(), //int srcH,
            a_src->pix_fmt(), //enum PixelFormat srcFormat,
            this->width(), //int dstW,
            this->height(), //int dstH,
            this->pix_fmt(), //enum PixelFormat dstFormat,
            a_sws_flags, //int flags,
            NULL, //SwsFilter *srcFilter,
            NULL, //SwsFilter *dstFilter,
            NULL  //const double *param
            );
    int v_scale_result = sws_scale(
            v_sws_ctx, //struct SwsContext *context,
            a_src->data(), //const uint8_t* const srcSlice[],
            a_src->linesize(), //const int srcStride[],
            0, //int srcSliceY,
            a_src->height(), //int srcSliceH,
            this->data(), //uint8_t* const dst[],
            this->linesize() //const int dstStride[]
            );
    Q_UNUSED(v_scale_result);
    sws_freeContext(v_sws_ctx);
}
void T_AVPicture::resizeForQImage(int a_depth, int a_width, int a_height)
{
    Q_ASSERT(a_depth==16||a_depth==32);
    switch(a_depth)
    {
    case 16:
        this->resize(PIX_FMT_RGB565, a_width, a_height);
        break;
    case 32:
        this->resize(PIX_FMT_BGRA, a_width, a_height);
        break;
    default:
        Q_ASSERT(0);
    }
}
QImage T_AVPicture::toQImage()
{
    switch(this->pix_fmt())
    {
    case PIX_FMT_RGB565:
        return QImage(this->data()[0], this->width(), this->height(), QImage::Format_RGB16);
        break;
    case PIX_FMT_BGRA:
        return QImage(this->data()[0], this->width(), this->height(), QImage::Format_RGB32);
        break;
    default:
        return QImage();
    }
}
void T_AVPicture::ctor_T_AVPicture(PixelFormat a_pix_fmt, int a_width, int a_height)
{
    m_num_bytes = 0;
    m_buffer = 0;
    p_reallocate(a_pix_fmt, a_width, a_height);
}
void T_AVPicture::p_reallocate(PixelFormat a_pix_fmt, int a_width, int a_height)
{
    m_pix_fmt = a_pix_fmt;
    m_width = a_width;
    m_height = a_height;
    int v_numBytes=avpicture_get_size(
            m_pix_fmt,
            m_width,
            m_height
            );
    if(m_num_bytes < v_numBytes)
    {
        m_num_bytes = v_numBytes;
        if(m_buffer) delete[] m_buffer;
        m_buffer=new uint8_t[m_num_bytes];
    }
    avpicture_fill(
            &m_av_picture,
            m_buffer,
            m_pix_fmt,
            m_width,
            m_height
            );
}
